{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 循环\n",
    "\n",
    "## 目标\n",
    "\n",
    "* 程序的三大流程\n",
    "* while 循环基本使用\n",
    "* break 和 continue\n",
    "* while 循环嵌套\n",
    "\n",
    "## 01. 程序的三大流程\n",
    "\n",
    "* 在程序开发中，一共有三种流程方式：\n",
    "    * **顺序** —— **从上向下**，顺序执行代码\n",
    "    * **分支** —— 根据条件判断，决定执行代码的 **分支**\n",
    "    * **循环** —— 让 **特定代码 重复** 执行\n",
    "\n",
    "    ![001_程序三大流程](./ras/001_程序三大流程.png)\n",
    "\n",
    "\n",
    "## 02. `while` 循环基本使用\n",
    "\n",
    "* 循环的作用就是让 **指定的代码** 重复的执行\n",
    "* `while` 循环最常用的应用场景就是 **让执行的代码** 按照 **指定的次数** **重复** 执行\n",
    "\n",
    "* 需求 —— 打印 5 遍 `Hello Python`\n",
    "* 思考 —— 如果要求打印 100 遍怎么办？\n",
    "\n",
    "### 2.1 `while` 语句基本语法\n",
    "\n",
    "```python\n",
    "初始条件设置 —— 通常是重复执行的 计数器\n",
    "\n",
    "while 条件(判断 计数器 是否达到 目标次数):\n",
    "    条件满足时，做的事情1\n",
    "    条件满足时，做的事情2\n",
    "    条件满足时，做的事情3\n",
    "    ...(省略)...\n",
    "    \n",
    "    处理条件(计数器 + 1)\n",
    "```\n",
    "\n",
    "**注意**：\n",
    "\n",
    "* `while` 语句以及缩进部分是一个 **完整的代码块**\n",
    "\n",
    "#### 第一个 while 循环\n",
    "\n",
    "**需求**\n",
    "\n",
    "* 打印 5 遍 Hello Python\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello Python\n",
      "Hello Python\n",
      "Hello Python\n",
      "Hello Python\n",
      "Hello Python\n",
      "循环结束后的 i = 6\n"
     ]
    }
   ],
   "source": [
    "# 1. 定义重复次数计数器\n",
    "i = 1\n",
    "\n",
    "# 2. 使用 while 判断条件\n",
    "while i <= 5:\n",
    "    # 要重复执行的代码\n",
    "    print(\"Hello Python\")\n",
    "\n",
    "    # 处理计数器 i\n",
    "    i = i + 1\n",
    "\n",
    "print(\"循环结束后的 i = %d\" % i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 注意：循环结束后，之前定义的计数器条件的数值是依旧存在的\n",
    "\n",
    "#### 死循环\n",
    "\n",
    "> 由于程序员的原因，**忘记** 在循环内部 **修改循环的判断条件**，导致循环持续执行，程序无法终止！\n",
    "\n",
    "### 2.2 赋值运算符\n",
    "\n",
    "* 在 Python 中，使用 `=` 可以给变量赋值\n",
    "* 在算术运算时，为了简化代码的编写，`Python` 还提供了一系列的 与 **算术运算符** 对应的 **赋值运算符**\n",
    "* 注意：**赋值运算符中间不能使用空格**\n",
    "\n",
    "| 运算符 | 描述 | 实例 |\n",
    "| --- | --- | --- |\n",
    "| = | 简单的赋值运算符 | c = a + b 将 a + b 的运算结果赋值为 c |\n",
    "| += | 加法赋值运算符 | c += a 等效于 c = c + a |\n",
    "| -= | 减法赋值运算符 | c -= a 等效于 c = c - a |\n",
    "| *= | 乘法赋值运算符\t | c *= a 等效于 c = c * a |\n",
    "| /= | 除法赋值运算符 | c /= a 等效于 c = c / a |\n",
    "| //= | 取整除赋值运算符 | c //= a 等效于 c = c // a |\n",
    "| %= | 取 **模** (余数)赋值运算符 | c %= a 等效于 c = c % a |\n",
    "| **= | 幂赋值运算符 | c **= a 等效于 c = c ** a |\n",
    "\n",
    "### 2.3 Python 中的计数方法\n",
    "\n",
    "常见的计数方法有两种，可以分别称为：\n",
    "\n",
    "* **自然计数法**（从 `1` 开始）—— 更符合人类的习惯\n",
    "* **程序计数法**（从 `0` 开始）—— 几乎所有的程序语言都选择从 0 开始计数\n",
    "\n",
    "因此，大家在编写程序时，应该尽量养成习惯：**除非需求的特殊要求，否则 循环 的计数都从 0 开始**\n",
    "\n",
    "### 2.4 循环计算\n",
    "\n",
    "> 在程序开发中，通常会遇到 **利用循环** **重复计算** 的需求\n",
    "\n",
    "遇到这种需求，可以：\n",
    "\n",
    "1. 在 `while` 上方定义一个变量，用于 **存放最终计算结果**\n",
    "2. 在循环体内部，每次循环都用 **最新的计算结果**，**更新** 之前定义的变量\n",
    "\n",
    "**需求**\n",
    "\n",
    "* 计算 0 ~ 100 之间所有数字的累计求和结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0~100之间的数字求和结果 = 5050\n"
     ]
    }
   ],
   "source": [
    "# 计算 0 ~ 100 之间所有数字的累计求和结果\n",
    "# 0. 定义最终结果的变量\n",
    "result = 0\n",
    "\n",
    "# 1. 定义一个整数的变量记录循环的次数\n",
    "i = 0\n",
    "\n",
    "# 2. 开始循环\n",
    "while i <= 100:\n",
    "\n",
    "    # 每一次循环，都让 result 这个变量和 i 这个计数器相加\n",
    "    result += i\n",
    "\n",
    "    # 处理计数器\n",
    "    i += 1\n",
    "\n",
    "print(\"0~100之间的数字求和结果 = %d\" % result)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 需求进阶\n",
    "\n",
    "* 计算 0 ~ 100 之间 所有 **偶数** 的累计求和结果\n",
    "\n",
    "开发步骤\n",
    "\n",
    "1. 编写循环 **确认** **要计算的数字**\n",
    "2. 添加 **结果** 变量，在循环内部 **处理计算结果**\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0~100之间偶数求和结果 = 2550\n"
     ]
    }
   ],
   "source": [
    "# 0. 最终结果\n",
    "result = 0\n",
    "\n",
    "# 1. 计数器\n",
    "i = 0\n",
    "\n",
    "# 2. 开始循环\n",
    "while i <= 100:\n",
    "\n",
    "    # 判断偶数\n",
    "    if i % 2 == 0:\n",
    "        result += i\n",
    "\n",
    "    # 处理计数器\n",
    "    i += 1\n",
    "\n",
    "print(\"0~100之间偶数求和结果 = %d\" % result)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 03. break 和 continue\n",
    "\n",
    "> `break` 和 `continue` 是专门在循环中使用的关键字\n",
    "\n",
    "* `break` **某一条件满足时**，退出循环，不再执行后续重复的代码\n",
    "* `continue` **某一条件满足时**，不执行后续重复的代码\n",
    "\n",
    "> `break` 和 `continue` 只针对 **当前所在循环** 有效\n",
    "\n",
    "![002_循环流程图-w400](./res/002_循环流程图.png)\n",
    "\n",
    "\n",
    "### 3.1 break\n",
    "\n",
    "* **在循环过程中**，如果 **某一个条件满足后**，**不** 再希望 **循环继续执行**，可以使用 `break` 退出循环\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n",
      "over\n"
     ]
    }
   ],
   "source": [
    "i = 0\n",
    "\n",
    "while i < 10:\n",
    "\n",
    "    # break 某一条件满足时，退出循环，不再执行后续重复的代码\n",
    "    # i == 3\n",
    "    if i == 3:\n",
    "        break\n",
    "\n",
    "    print(i)\n",
    "\n",
    "    i += 1\n",
    "\n",
    "print(\"over\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> `break` 只针对当前所在循环有效\n",
    "\n",
    "### 3.2 continue\n",
    "\n",
    "* **在循环过程中**，如果 **某一个条件满足后**，**不** 希望 **执行循环代码，但是又不希望退出循环**，可以使用 `continue`\n",
    "* 也就是：在整个循环中，**只有某些条件**，不需要执行循环代码，而其他条件都需要执行\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "6\n",
      "8\n",
      "9\n"
     ]
    }
   ],
   "source": [
    "i = 0\n",
    "\n",
    "while i < 10:\n",
    "\n",
    "    # 当 i == 7 时，不希望执行需要重复执行的代码\n",
    "    if i == 7:\n",
    "        # 在使用 continue 之前，同样应该修改计数器\n",
    "        # 否则会出现死循环\n",
    "        i += 1\n",
    "\n",
    "        continue\n",
    "\n",
    "    # 重复执行的代码\n",
    "    print(i)\n",
    "\n",
    "    i += 1\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 需要注意：使用 `continue` 时，**条件处理部分的代码，需要特别注意**，不小心会出现 **死循环**\n",
    "\n",
    "> `continue` 只针对当前所在循环有效\n",
    "\n",
    "## 04. `while` 循环嵌套\n",
    "\n",
    "### 4.1 循环嵌套\n",
    "\n",
    "* `while` 嵌套就是：`while` 里面还有 `while`\n",
    "\n",
    "```python\n",
    "while 条件 1:\n",
    "    条件满足时，做的事情1\n",
    "    条件满足时，做的事情2\n",
    "    条件满足时，做的事情3\n",
    "    ...(省略)...\n",
    "    \n",
    "    while 条件 2:\n",
    "        条件满足时，做的事情1\n",
    "        条件满足时，做的事情2\n",
    "        条件满足时，做的事情3\n",
    "        ...(省略)...\n",
    "    \n",
    "        处理条件 2\n",
    "    \n",
    "    处理条件 1\n",
    "```\n",
    "\n",
    "### 4.2 循环嵌套演练 —— 九九乘法表\n",
    "\n",
    "#### 第 1 步：用嵌套打印小星星\n",
    "\n",
    "**需求**\n",
    "\n",
    "* 在控制台连续输出五行 `*`，每一行星号的数量依次递增\n",
    "\n",
    "```\n",
    "*\n",
    "**\n",
    "***\n",
    "****\n",
    "*****\n",
    "```\n",
    "\n",
    "* 使用字符串 * 打印\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "*\n",
      "**\n",
      "***\n",
      "****\n",
      "*****\n"
     ]
    }
   ],
   "source": [
    "# 1. 定义一个计数器变量，从数字1开始，循环会比较方便\n",
    "row = 1\n",
    "\n",
    "while row <= 5:\n",
    "\n",
    "    print(\"*\" * row)\n",
    "\n",
    "    row += 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 第 2 步：使用循环嵌套打印小星星\n",
    "\n",
    "**知识点** 对 `print` 函数的使用做一个增强\n",
    "\n",
    "* 在默认情况下，`print` 函数输出内容之后，会自动在内容末尾增加换行\n",
    "* 如果不希望末尾增加换行，可以在 `print` 函数输出内容的后面增加 `, end=\"\"`\n",
    "* 其中 `\"\"` 中间可以指定 `print` 函数输出内容之后，继续希望显示的内容\n",
    "\n",
    "* 语法格式如下：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "*\n"
     ]
    }
   ],
   "source": [
    "# 向控制台输出内容结束之后，不会换行\n",
    "print(\"*\", end=\"\")\n",
    "\n",
    "# 单纯的换行\n",
    "print(\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> `end=\"\"` 表示向控制台输出内容结束之后，不会换行\n",
    "\n",
    "**假设** `Python` **没有提供** 字符串的 `*` 操作 **拼接字符串**\n",
    "\n",
    "**需求**\n",
    "\n",
    "* 在控制台连续输出五行 `*`，每一行星号的数量依次递增\n",
    "\n",
    "```\n",
    "*\n",
    "**\n",
    "***\n",
    "****\n",
    "*****\n",
    "```\n",
    "\n",
    "**开发步骤**\n",
    "\n",
    "* 1> 完成 5 行内容的简单输出\n",
    "* 2> 分析每行内部的 `*` 应该如何处理？\n",
    "    * 每行显示的星星和当前所在的行数是一致的\n",
    "    * 嵌套一个小的循环，专门处理每一行中 `列` 的星星显示  \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "*\n",
      "**\n",
      "***\n",
      "****\n",
      "*****\n"
     ]
    }
   ],
   "source": [
    "row = 1\n",
    "\n",
    "while row <= 5:\n",
    "\n",
    "    # 假设 python 没有提供字符串 * 操作\n",
    "    # 在循环内部，再增加一个循环，实现每一行的 星星 打印\n",
    "    col = 1\n",
    "\n",
    "    while col <= row:\n",
    "        print(\"*\", end=\"\")\n",
    "\n",
    "        col += 1\n",
    "\n",
    "    # 每一行星号输出完成后，再增加一个换行\n",
    "    print(\"\")\n",
    "\n",
    "    row += 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 第 3 步： 九九乘法表\n",
    "\n",
    "**需求** 输出 九九乘法表，格式如下：\n",
    "\n",
    "```\n",
    "1 * 1 = 1\t\n",
    "1 * 2 = 2\t2 * 2 = 4\t\n",
    "1 * 3 = 3\t2 * 3 = 6\t3 * 3 = 9\t\n",
    "1 * 4 = 4\t2 * 4 = 8\t3 * 4 = 12\t4 * 4 = 16\t\n",
    "1 * 5 = 5\t2 * 5 = 10\t3 * 5 = 15\t4 * 5 = 20\t5 * 5 = 25\t\n",
    "1 * 6 = 6\t2 * 6 = 12\t3 * 6 = 18\t4 * 6 = 24\t5 * 6 = 30\t6 * 6 = 36\t\n",
    "1 * 7 = 7\t2 * 7 = 14\t3 * 7 = 21\t4 * 7 = 28\t5 * 7 = 35\t6 * 7 = 42\t7 * 7 = 49\t\n",
    "1 * 8 = 8\t2 * 8 = 16\t3 * 8 = 24\t4 * 8 = 32\t5 * 8 = 40\t6 * 8 = 48\t7 * 8 = 56\t8 * 8 = 64\t\n",
    "1 * 9 = 9\t2 * 9 = 18\t3 * 9 = 27\t4 * 9 = 36\t5 * 9 = 45\t6 * 9 = 54\t7 * 9 = 63\t8 * 9 = 72\t9 * 9 = 81\n",
    "\n",
    "```\n",
    "\n",
    "**开发步骤**\n",
    "\n",
    "* 1. 打印 9 行小星星\n",
    "\n",
    "```\n",
    "*\n",
    "**\n",
    "***\n",
    "****\n",
    "*****\n",
    "******\n",
    "*******\n",
    "********\n",
    "*********\n",
    "```\n",
    "\n",
    "* 2. 将每一个 `*` 替换成对应的行与列相乘\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 * 1 = 1\t\n",
      "1 * 2 = 2\t2 * 2 = 4\t\n",
      "1 * 3 = 3\t2 * 3 = 6\t3 * 3 = 9\t\n",
      "1 * 4 = 4\t2 * 4 = 8\t3 * 4 = 12\t4 * 4 = 16\t\n",
      "1 * 5 = 5\t2 * 5 = 10\t3 * 5 = 15\t4 * 5 = 20\t5 * 5 = 25\t\n",
      "1 * 6 = 6\t2 * 6 = 12\t3 * 6 = 18\t4 * 6 = 24\t5 * 6 = 30\t6 * 6 = 36\t\n",
      "1 * 7 = 7\t2 * 7 = 14\t3 * 7 = 21\t4 * 7 = 28\t5 * 7 = 35\t6 * 7 = 42\t7 * 7 = 49\t\n",
      "1 * 8 = 8\t2 * 8 = 16\t3 * 8 = 24\t4 * 8 = 32\t5 * 8 = 40\t6 * 8 = 48\t7 * 8 = 56\t8 * 8 = 64\t\n",
      "1 * 9 = 9\t2 * 9 = 18\t3 * 9 = 27\t4 * 9 = 36\t5 * 9 = 45\t6 * 9 = 54\t7 * 9 = 63\t8 * 9 = 72\t9 * 9 = 81\t\n"
     ]
    }
   ],
   "source": [
    "# 定义起始行\n",
    "row = 1\n",
    "\n",
    "# 最大打印 9 行\n",
    "while row <= 9:\n",
    "    # 定义起始列\n",
    "    col = 1\n",
    "\n",
    "    # 最大打印 row 列\n",
    "    while col <= row:\n",
    "\n",
    "        # end = \"\"，表示输出结束后，不换行\n",
    "        # \"\\t\" 可以在控制台输出一个制表符，协助在输出文本时对齐\n",
    "        print(\"%d * %d = %d\" % (col, row, row * col), end=\"\\t\")\n",
    "\n",
    "        # 列数 + 1\n",
    "        col += 1\n",
    "\n",
    "    # 一行打印完成的换行\n",
    "    print(\"\")\n",
    "\n",
    "    # 行数 + 1\n",
    "    row += 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**字符串中的转义字符**\n",
    "\n",
    "* `\\t` 在控制台输出一个 **制表符**，协助在输出文本时 **垂直方向** 保持对齐\n",
    "* `\\n` 在控制台输出一个 **换行符**\n",
    "\n",
    "> **制表符** 的功能是在不使用表格的情况下在 **垂直方向** 按列对齐文本\n",
    "\n",
    "| 转义字符 | 描述 |\n",
    "| --- | --- |\n",
    "| \\\\\\\\ | 反斜杠符号 |\n",
    "| \\\\' | 单引号 |\n",
    "| \\\\\" | 双引号 |\n",
    "| \\n | 换行 |\n",
    "| \\t | 横向制表符 |\n",
    "| \\r | 回车 |\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
